package be.pluyckx.batteryprogress.data.history;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.util.Date;

import be.pluyckx.batteryprogress.application.Constants;
import be.pluyckx.batteryprogress.data.ObservableListImpl;
import be.pluyckx.batteryprogress.data.history.snapshot.ProcessSnapshot;
import be.pluyckx.batteryprogress.database.BatteryLevelFileStorage;

/**
 * Created by Philip on 26/08/13.
 */
public class BatteryLevel extends ObservableListImpl implements BatteryLevelFileStorage.FileWritable, Comparable<BatteryLevel> {
  public static final String TAG = "BatteryLevel";

  public static final int STATE_DISCHARGING = 1;
  public static final int STATE_CHARGING = 2;

  private final int mBatteryLevel;
  private final int mBatteryScale;
  private final float mBatteryPercent;
  private final long mDate;
  private final long mElapsed;
  private final int mState;
  private ProcessSnapshot mProcessesSnapshot;
  private boolean isSnapshotSet = false;

  /**
   * Create a new BatteryLevel object
   *
   * @param date         In ms after 1 january 1970
   * @param elapsed      In seconds
   * @param batteryLevel The current battery level
   * @param scale        The scale
   */
  public BatteryLevel(int state, long date, long elapsed, int batteryLevel, int scale) {
    mBatteryLevel = batteryLevel;
    mBatteryScale = scale;
    mBatteryPercent = ((float) mBatteryLevel) / ((float) mBatteryScale);
    mDate = date;
    mElapsed = elapsed;
    mState = state;
  }

  public BatteryLevel(DataInputStream dis) throws IOException {
    this.mBatteryLevel = dis.readInt();
    this.mBatteryScale = dis.readInt();
    this.mBatteryPercent = ((float) mBatteryLevel) / ((float) mBatteryScale);
    this.mState = dis.readInt();
    this.mDate = dis.readLong();
    this.mElapsed = dis.readLong();
    this.isSnapshotSet = (dis.readByte() == 1 ? true : false);
    if (isSnapshotSet) {
      mProcessesSnapshot = new ProcessSnapshot(dis);
    }
  }


  @Override
  public int streamSize() {
    return Integer.SIZE / 8 * 3 + Long.SIZE / 8 * 2 + 1 + (isSnapshotSet ? mProcessesSnapshot.streamSize() : 0);
  }

  @Override
  public void write(DataOutputStream dos) throws IOException {
    dos.writeInt(this.mBatteryLevel);
    dos.writeInt(this.mBatteryScale);
    dos.writeInt(this.mState);
    dos.writeLong(this.mDate);
    dos.writeLong(this.mElapsed);
    dos.writeByte(this.isSnapshotSet ? 1 : 0);
    if (isSnapshotSet) {
      mProcessesSnapshot.write(dos);
    }
  }

  /**
   * Set the snapshot. This method only sets the snapshot the first time. When setting the snapshot
   * a second time, it is ignored.
   *
   * @param snapshot
   */
  public void setSnapshot(ProcessSnapshot snapshot) {
    if (!isSnapshotSet) {
      synchronized (snapshot) {
        if (!isSnapshotSet) {
          mProcessesSnapshot = snapshot;
          isSnapshotSet = true;
          fireDataChanged(this, null);
        }
      }
    }
  }

  public ProcessSnapshot getProcessesSnapshot() {
    return mProcessesSnapshot;
  }

  public int getBatteryLevel() {
    return mBatteryLevel;
  }

  public int getBatteryScale() {
    return mBatteryScale;
  }

  public float getBatteryLevelPercentage() {
    return mBatteryPercent;
  }

  public String getBatteryLevelPercentageAsString() {
    DecimalFormat df = new DecimalFormat("0%");
    return df.format(mBatteryPercent);
  }

  public long getDate() {
    return mDate;
  }

  public long getElapsed() {
    return mElapsed;
  }

  public String getDateString() {
    return Constants.dateTimeLongFormat.format(new Date(mDate));
  }

  public int getState() {
    return mState;
  }

  public boolean equals(Object o) {
    if (o instanceof BatteryLevel) {
      BatteryLevel bc = (BatteryLevel) o;
      return (bc.mBatteryLevel == mBatteryLevel && bc.mDate == mDate && bc.mElapsed == mElapsed);
    } else {
      return false;
    }
  }

  public String getBatteryLevelAsString() {
    StringBuilder sb = new StringBuilder();
    sb.append(mBatteryLevel);
    sb.append("/");
    sb.append(mBatteryScale);
    sb.append(" (");
    sb.append(getBatteryLevelPercentageAsString());
    sb.append(")");

    return sb.toString();
  }

  public String toString() {
    StringBuilder sb = new StringBuilder();

    sb.append(DateFormat.getDateTimeInstance().format(new Date(mDate * 1000)));
    sb.append(" ");
    sb.append(getBatteryLevel());
    sb.append('/');
    sb.append(getBatteryScale());
    sb.append(" (");
    sb.append(getBatteryLevelPercentage());
    sb.append(")");

    return sb.toString();
  }

  @Override
  public int compareTo(BatteryLevel batteryLevel) {
    long ret = mDate - batteryLevel.mDate;
    if (ret < 0) {
      return -1;
    } else if (ret == 0) {
      return 0;
    } else {
      return 1;
    }
  }
}